﻿// *---------------------------------------------------------------------------------------------------------*
// Solution:         JwikIDE									
// Project:           JwiKIDE								
// Source File:    MainForm.cs									
// *---------------------------------------------------------------------------------------------------------*
// 
// © 2012 Digital Six Labs, LLC All Rights Reserved
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
// and associated documentation files (the "Software"), to deal in the Software without restriction, 
// including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 
// and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 
// subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in all copies or substantial 
// portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 
// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// 
// 
// 
// 


namespace JwiKIDE
{
    using System.Diagnostics;
    using System.Drawing;
    using System.IO;
    using System.Xml.Serialization;
    using System;
    using System.Windows.Forms;

    using JwiKIDE.Controls;
    using JwiKIDE.JavaClassFileClasses;
    using JwiKIDE.ProjectManagement;

    public partial class MainForm : Form
    {
        private SourceControl solutionExplorer;
        //private InputOutputSymbolToolbox ioToolBox = new InputOutputSymbolToolbox();
        //private OutputWindow outputWindow = new OutputWindow();
        public string ClassPath { get; set; }
        public Project CurrentProject { get; set; }

        public MainForm()
        {
            InitializeComponent();
        }

        
 
        private void OpenClassFile(string fn)
        {
            var sd = new TextDocument(); 
            sd.LoadFromFile(fn);
            sd.Anchor = AnchorStyles.Bottom | AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Left;
            sd.DocumentDirty += new EventHandler(this.DocumentDirtyHandler);

            var tp = new TabPage { Text = Path.GetFileName(fn) };

            tp.Controls.Add(sd);
            tabDocuments.TabPages.Add(tp);
            sd.Dock = DockStyle.Fill;
            tabDocuments.SelectTab(tp);
            sd.Tag = tp;
            //sd.DeselectAll();
        }

        void DocumentDirtyHandler(object sender, EventArgs e)
        {
            TextDocument td = sender as TextDocument;

            if(td!=null)
            {
                TabPage tp = td.Tag as TabPage;
                tp.Text = td.FileName + "*";
            }
        }
        private void OpenJavaSourceFileToolStripMenuItemClick(object sender, EventArgs e)
        {
            var ofd1 = new OpenFileDialog { Filter = "Java source files (*.java)|*.java|Native files (*.native)|*.native|Projects (*.ucjproject)|*.ucjproject" };
            if (ofd1.ShowDialog() != DialogResult.OK)
            {
                return;
            }
            switch(Path.GetExtension(ofd1.FileName))
            {
                case ".java":
                    this.OpenClassFile(ofd1.FileName);
                    break;
                case ".native":
                    break;
                case ".ucjproject":
                    CurrentProject = this.OpenProjectFile(ofd1.FileName);
                    this.EnableProjectRelatedMenuItems();
                    //solutionExplorer.Update(CurrentProject);
                    break;
            }
            
        }

        private void MainFormLoad(object sender, EventArgs e)
        {

            solutionExplorer = sourceControl1;
            solutionExplorer.OpenFileEvent += new SourceControl.OpenFileEventDelegate(solutionExplorer_OpenFileEvent);
        }

        void ImageListBox1_MouseDown(object sender, MouseEventArgs e)
        {
            //ioToolBox.ImageListBox1.DoDragDrop(ioToolBox.ImageListBox1.SelectedItem, DragDropEffects.Copy);
        }

        bool IsFileOpen(string fileName)
        {
            
            foreach(TabPage tp in tabDocuments.TabPages)
            {
                
                    if (tp.Text.TrimEnd(new[] {'*'}) == fileName) 
                        return true;
                
            }
            
            return false;
        }
        void solutionExplorer_OpenFileEvent(string type, string fileName)
        {
            
            switch (type)
            {
                case "class":
                    if(!this.IsFileOpen(fileName))
                        this.OpenClassFile(CurrentProject.RootPath+"\\"+fileName);
                    break;
                case "native":
                    if(!this.IsFileOpen(fileName))
                        this.OpenClassFile(CurrentProject.RootPath+"\\"+fileName);
                    break;
            }
             
        }
        
        private void ExitToolStripMenuItem1Click(object sender, EventArgs e)
        {
            this.Close();
        }
        
        private void ProjectToolStripMenuItem1Click(object sender, EventArgs e)
        {
            
            var npf = new NewProjectForm();

            if(npf.ShowDialog()==DialogResult.OK)
            {
                var project = new Project
                    {
                        Name = npf.tbName.Text, 
                        Description = npf.tbDescription.Text, 
                        RootPath = npf.tbLocation.Text
                    };

                CurrentProject = project;
                EnableProjectRelatedMenuItems();
                CloseAllFiles();
                solutionExplorer.Update(CurrentProject);
            }
             
        }

        private void CloseAllFiles()
        {
            /*
            foreach (IDockContent dc in dockPanel1.Contents)
            {
                if (dc is SourceDocument)
                {
                    var doc = (SourceDocument)dc;
                    if (doc.TabText.EndsWith("*"))
                    {
                        if (MessageBox.Show("Save file?", "File", MessageBoxButtons.YesNo) == DialogResult.Yes) doc.SaveFile();
                    }
                    doc.Close();
                }
            }
             * */
        }
        
        private void EnableProjectRelatedMenuItems()
        {
            menuItemAddExistingSourceFile.Enabled = true;
            menuItemAddNewNativeFile.Enabled = true;
            menuItemAddNewSourceFile.Enabled = true;
            menuItemBuildTool.Enabled = true;
            menuItemGenerateVMFile.Enabled = true;
            menuItemRemoveFile.Enabled = true;
            menuItemSaveProject.Enabled = true;
            menuItemCloseProject.Enabled = true;
            menuItemAddExistingNativeFile.Enabled = true;
            menuItemStartupFile.Enabled = true;
        }
        private void DisableProjectRelatedMenuItems()
        {
            menuItemAddExistingSourceFile.Enabled = false;
            menuItemAddNewNativeFile.Enabled = false;
            menuItemAddNewSourceFile.Enabled = false;
            menuItemBuildTool.Enabled = false;
            menuItemGenerateVMFile.Enabled = false;
            menuItemRemoveFile.Enabled = false;
            menuItemSaveProject.Enabled = false;
            menuItemCloseProject.Enabled = false;
            menuItemAddExistingNativeFile.Enabled = false;
            menuItemStartupFile.Enabled = false;
        }
        
        void SaveProjectFile()
        {
            
            var fileName = CurrentProject.RootPath + "\\" + CurrentProject.Name + ".ucjproject";
            var serializer = new XmlSerializer(typeof(Project));
            var textWriter = new StreamWriter(fileName);
            serializer.Serialize(textWriter, CurrentProject);
            textWriter.Close();
             
        }
        void CloseProjectFile()
        {
            this.SaveProjectFile();
            CurrentProject = null;
            this.DisableProjectRelatedMenuItems();
        }
        
        private void SaveProjectToolStripMenuItemClick(object sender, EventArgs e)
        {
            this.SaveProjectFile();
        }
        
        private void menuItemCloseProject_Click(object sender, EventArgs e)
        {
            this.CloseProjectFile();
            solutionExplorer.Update(CurrentProject);
            solutionExplorer.Invalidate(true);
        }
       
        private void openProjectToolStripMenuItem_Click(object sender, EventArgs e)
        {
            openFileDialog1.Filter = "Project File (*.ucjproject) | *.ucjproject";
            if(openFileDialog1.ShowDialog()==DialogResult.OK)
            {
                CurrentProject = OpenProjectFile(openFileDialog1.FileName);
                this.EnableProjectRelatedMenuItems();
                solutionExplorer.Update(CurrentProject);
            }
        }

        
        private Project OpenProjectFile(string fileName)
        {
            var deserializer = new XmlSerializer(typeof(Project));
            var textReader = new StreamReader(fileName);
            Project rtval= (Project)deserializer.Deserialize(textReader);
            textReader.Close();
            return rtval;
        }
        
        private void menuItemAddNewSourceFile_Click(object sender, EventArgs e)
        {
            var sd = new TextDocument(CurrentProject.RootPath+"\\Unnamed" + (this.CurrentProject.ClassFiles.Count + 1) + ".java");
            sd.DocumentDirty += new EventHandler(this.DocumentDirtyHandler);
            sd.Anchor = AnchorStyles.Bottom | AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Left;
            
            var tp = new TabPage { Text = sd.FileName };
            sd.Tag = tp;
            CurrentProject.ClassFiles.Add(tp.Text);
            if (CurrentProject.ClassFiles.Count == 1) CurrentProject.MainAppFile = tp.Text;
            solutionExplorer.Update(CurrentProject);
            this.SaveProjectFile();
            tp.Controls.Add(sd);
            tabDocuments.TabPages.Add(tp);
            sd.Dock = DockStyle.Fill;
            tabDocuments.SelectTab(tp);
        }

        private void saveAsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if(tabDocuments.SelectedTab.Controls[0] is TextDocument)
            //if(dockPanel1.ActiveDocument is SourceDocument)
            {
                //var doc = (SourceDocument)dockPanel1.ActiveDocument;
                TextDocument doc = tabDocuments.SelectedTab.Controls[0] as TextDocument;
                //string currentName = doc.TabText.TrimEnd(new[] { '*' });
                string currentName = tabDocuments.SelectedTab.Text.TrimEnd(new[] { '*' });
                var sd = new SaveFileDialog();
                if (Path.GetExtension(doc.FileName) == ".java")
                    sd.Filter = "Java files (*.java)|*.java";
                else if (Path.GetExtension(doc.FileName) == ".native")
                    sd.Filter = "Native Files (*.native)|*.native";
                if(sd.ShowDialog()==DialogResult.OK)
                {
                    tabDocuments.SelectedTab.Text = Path.GetFileName(sd.FileName);
                    if (CurrentProject.MainAppFile == currentName) CurrentProject.MainAppFile = tabDocuments.SelectedTab.Text;
                    ChangeClassFileName(currentName, tabDocuments.SelectedTab.Text);
                    solutionExplorer.Update(CurrentProject);
                    doc.SaveToFile(sd.FileName);
                    this.SaveProjectFile();
                }
            }
            
        }

        private void ChangeClassFileName(string currentName, string p)
        {
            
            for (int i = 0; i < CurrentProject.ClassFiles.Count; i++)
                if (CurrentProject.ClassFiles[i] == currentName) 
                    CurrentProject.ClassFiles[i] = p;
            for (int i = 0; i < CurrentProject.NativeClassFiles.Count; i++)
                if (CurrentProject.NativeClassFiles[i] == currentName)
                    CurrentProject.NativeClassFiles[i] = p;
             
        }

        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var textDocument = this.tabDocuments.SelectedTab.Controls[0] as TextDocument;
            
            if (textDocument.FirstSave )
                saveAsToolStripMenuItem_Click(sender, e);
            else
            {

                // only save a dirty document
                if (!textDocument.Dirty) return;
                tabDocuments.SelectedTab.Text = tabDocuments.SelectedTab.Text.TrimEnd(new char[] { '*' });
                if (textDocument != null)
                {
                    textDocument.SaveToFile();
                }
            }

        }

        private void saveAllToolStripMenuItem_Click(object sender, EventArgs e)
        {
            
            foreach(TabPage tp in tabDocuments.TabPages)
            {
                var dc = tp.Controls[0] as TextDocument;

                tabDocuments.SelectedTab.Text=tabDocuments.SelectedTab.Text.TrimEnd(new char[] { '*' });
                if(dc!=null)
                {
                    var doc = dc;
                    if(tp.Text.EndsWith("*"))
                    {
                        doc.SaveToFile();
                    }
                }
            }
            this.SaveProjectFile();
             
        }

        private void closeFileToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if(tabDocuments.SelectedTab.Controls[0] is TextDocument)
            {
                var doc = tabDocuments.SelectedTab.Controls[0] as TextDocument;

                if (tabDocuments.SelectedTab.Text.EndsWith("*"))
                {
                    if (MessageBox.Show("Save file?", "File", MessageBoxButtons.YesNo) == DialogResult.Yes)
                        doc.SaveToFile();
                }
                tabDocuments.TabPages.Remove(tabDocuments.SelectedTab);

            }

        }

        private void solutionExplorerToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //solutionExplorer.Show(dockPanel1, DockState.DockLeft);
        }

        private void menuItemBuildTool_Click(object sender, EventArgs e)
        {
            
            if (!Directory.Exists(CurrentProject.RootPath + "\\classes")) 
                Directory.CreateDirectory(CurrentProject.RootPath + "\\classes");
            // create a build file and call JavaC
            var tw = new StreamWriter(CurrentProject.RootPath + "\\buildfile");
            foreach(string s in CurrentProject.ClassFiles)
                tw.WriteLine(CurrentProject.RootPath + "\\"+s);
            tw.Close();
            var startInfo = new ProcessStartInfo();
            startInfo.FileName = "javac";
            startInfo.Arguments = " -classpath " + CurrentProject.RootPath
                +" -d "+CurrentProject.RootPath+"\\classes @"+CurrentProject.RootPath+"\\buildfile";
            startInfo.RedirectStandardError = true;
            //startInfo.RedirectStandardOutput = true;
            startInfo.UseShellExecute = false;
            startInfo.CreateNoWindow = true;
            var javac = Process.Start(startInfo);
            var errors = javac.StandardError.ReadToEnd();
            javac.WaitForExit(10000);
            
            if(errors=="")
            {
                tbOutputWindow.Text += "-----------------------\r\n";
                tbOutputWindow.Text += "Compiled with no errors.\r\n";
            }
            else
            {
                tbOutputWindow.Text += "-----------------------\r\n";
                tbOutputWindow.Text += errors;
            }
            
        }

        private void menuItemRemoveFile_Click(object sender, EventArgs e)
        {
            
            if (CurrentProject == null) return;
            string fileName = solutionExplorer.GetSelectedFile();
            if(fileName!=string.Empty)
            {
                if(Path.GetExtension(fileName)==".java")
                {
                    string s2r = string.Empty;
                    foreach (var s in CurrentProject.ClassFiles)
                        if (fileName == s) s2r=s;
                    if (s2r != string.Empty) CurrentProject.ClassFiles.Remove(s2r);

                }
                else if(Path.GetExtension(fileName) == ".native")
                {
                    string s2r = string.Empty;
                    foreach (var s in CurrentProject.NativeClassFiles)
                        if (fileName == s) s2r = s;
                    if (s2r != string.Empty) CurrentProject.NativeClassFiles.Remove(s2r);
                }
                if(MessageBox.Show("Delete file from disk as well?","Remove File",MessageBoxButtons.YesNo)==DialogResult.Yes)
                    File.Delete(CurrentProject.RootPath + "\\" + fileName);
                solutionExplorer.Update(CurrentProject);
                this.SaveProjectFile();
            }
            
        }

        private void menuItemStartupFile_Click(object sender, EventArgs e)
        {
            //string selectedFile = solutionExplorer.GetSelectedFile();
            //if (selectedFile != string.Empty) CurrentProject.MainAppFile = selectedFile;
        }

        private void menuItemGenerateVMFile_Click(object sender, EventArgs e)
        {
            
            var classFileName = Path.GetFileNameWithoutExtension(CurrentProject.MainAppFile) + ".class";
            
            try
            {
                ConfigFile.Clear();
                ClassLoader.Clear();
                var vmFileName = Path.GetFileNameWithoutExtension(CurrentProject.MainAppFile) + ".vmfile";
                ConfigFile.NativeFileNames = CurrentProject.NativeClassFiles;
                ConfigFile.MaxSize = 512;
                ConfigFile.NativePath = CurrentProject.RootPath;
                ConfigFile.LoadNativeFiles();
                ClassLoader.ClassPath = CurrentProject.RootPath + "\\classes";
                ClassLoader.Load(classFileName);
                if (!Directory.Exists(CurrentProject.RootPath + "\\output\\")) 
                    Directory.CreateDirectory(CurrentProject.RootPath + "\\output\\");
                // We have completely loaded and disected the class file, now use it to generate a VM file image for the uC Java VM
                VMFile.Generate(CurrentProject.RootPath + "\\output\\" + vmFileName);
                tbOutputWindow.Text += "---------------------------\r\n";
                tbOutputWindow.Text+="Class file has been parsed and .VMFile & .H files have been written.\r\n";
            }
            catch (IOException ioException)
            {
                MessageBox.Show("Problem loading classes: " + ioException.Message, "Error");
            }
            
        }

        private void menuItemAddExistingSourceFile_Click(object sender, EventArgs e)
        {
            openFileDialog1.Filter = "Java source files (*.java)|*.java";
            if(openFileDialog1.ShowDialog()==DialogResult.OK)
            {
                var sd = new TextDocument();
                sd.DocumentDirty += new EventHandler(this.DocumentDirtyHandler);
                sd.Anchor = AnchorStyles.Bottom | AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Left;
                string fn = Path.GetFileName(openFileDialog1.FileName);
                sd.Tag = fn;
                if (!CurrentProject.ClassFiles.Contains(fn))
                    CurrentProject.ClassFiles.Add(fn);
                solutionExplorer.Update(CurrentProject);
                this.SaveProjectFile();
                sd.Dock = DockStyle.Fill;
            }
        }
        private void menuItemAddNewNativeFile_Click(object sender, EventArgs e)
        {
            var sd = new TextDocument(CurrentProject.RootPath+"\\Unnamed" + (this.CurrentProject.NativeClassFiles.Count + 1) + ".native");
            sd.DocumentDirty += new EventHandler(this.DocumentDirtyHandler);
            sd.Anchor = AnchorStyles.Bottom | AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Left;

            var tp = new TabPage { Text = sd.FileName };
            sd.Tag = tp;
            CurrentProject.NativeClassFiles.Add(tp.Text);
            solutionExplorer.Update(CurrentProject);
            this.SaveProjectFile();
            tp.Controls.Add(sd);
            tabDocuments.TabPages.Add(tp);
            sd.Dock = DockStyle.Fill;
            tabDocuments.SelectTab(tp);
        }

        private void menuItemAddExistingNativeFile_Click(object sender, EventArgs e)
        {
            openFileDialog1.Filter = "Native files (*.native)|*.native";
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                var sd = new TextDocument();
                sd.DocumentDirty += new EventHandler(this.DocumentDirtyHandler);
                sd.Anchor = AnchorStyles.Bottom | AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Left;
                string fn = Path.GetFileName(openFileDialog1.FileName);
                sd.Tag = fn;

                if (!CurrentProject.NativeClassFiles.Contains(fn))
                    CurrentProject.NativeClassFiles.Add(fn);
                solutionExplorer.Update(CurrentProject);
                this.SaveProjectFile();
                sd.Dock = DockStyle.Fill;
            }
        }

        private void outputWindowToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //outputWindow.Show(dockPanel1,DockState.DockBottom);
        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {

        }

        private void toolStrip1_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {

        }
        
    }
}
